/*
 *  Copyright (C) 2011  Clint Priest
 *
 *  This file is part of pklib.
 *
 *  pklib is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  pklib is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with pklib.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
 
 
/** Creates getters/setters on this class for each parameter specified in the map */
var PrefsMapper = Class.create({
	/**
	 *	@param BasePath string 	- String representing the prefix for automatic preference names based on property name of map
	 *	@param map object		- Object map of { PropertyTitle: { Parameters } }
	 *			Parameters:		(Required) Type: 		bool || int || char
	 *							(Required) Default:		Default Value of Preference
	 *							(Optional) Name:		Full preference path, defaults to {BasePath}.{PropertyTitle}
	 */
	initialize: function(BasePath, map) {
		this.BasePath = BasePath;
		this.map = map || {};
		this.pref = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);

		Object.keys(this.map).forEach( function(Property) {
			this.map[Property].Type = this.map[Property].Type || 'char';
			this.map[Property].Path = (this.map[Property].Name && this.map[Property].Name[0] == '.' && this.BasePath + this.map[Property].Name) || (this.BasePath + '.' + Property);

			Object.defineProperty(this, Property, {
				get:	function() { return this.GetPref(Property); },
				set:	function(x) { this.SetPref(Property, x); }
			});

			/* Ensure the value or default value is stored */
			try { this[Property] = this[Property]; }
				catch(e) { Log.Warning('Unable to retrieve or set preference: ' + this.map[Property].Path + '\r\n' + e.toString()); }
		}, this);
	},
	GetPref: function(Property) {
		if(this.pref.prefHasUserValue(this.map[Property].Path) == false)
			return this.map[Property].Default;
		switch(this.map[Property].Type) {
			case 'bool':	return this.pref.getBoolPref(this.map[Property].Path);
			case 'int':		return this.pref.getIntPref(this.map[Property].Path);
			case 'char':	return this.pref.getCharPref(this.map[Property].Path);
		}
	},
	SetPref: function(Property, Value) {
		if(Value == undefined)
			Value = this.map[Property].Default;

		switch(this.map[Property].Type) {
			case 'bool':	return this.pref.setBoolPref(this.map[Property].Path, Value);
			case 'int':		return this.pref.setIntPref(this.map[Property].Path, Value);
			case 'char':	return this.pref.setCharPref(this.map[Property].Path, Value);
		}
	},
	TranslatePref: function(Property, Map) {
		var PreviousValue;

		switch(this.pref.getPrefType(this.map[Property].Path)) {
			case this.pref.PREF_STRING:	PreviousValue = this.pref.getCharPref(this.map[Property].Path);	break;
			case this.pref.PREF_INT:	PreviousValue = this.pref.getIntPref(this.map[Property].Path);	break;
			case this.pref.PREF_BOOL:	PreviousValue = this.pref.getBoolPref(this.map[Property].Path);	break;
		}
		this.pref.deleteBranch(this.map[Property].Path);
		this[Property] = Map[PreviousValue];
		Log.Warning("Translated Preference (" + this.map[Property].Path + ") from " + PreviousValue + " to " + this[Property]);
	}
} );


/**
* Automatic handling of load/save of preferences dialog based on prefstring="" attribute
* 	and default element to pref datatype mapping
*/
var PrefsDialogMapper = Class.create( {
	TypeMap: {
		radiogroup:		{ Property: 'value',		 	Type: 'char' },
		menulist:		{ Property: 'selectedIndex', 	Type: 'int' },
		colorpicker:	{ Property: 'color', 			Type: 'char' },
		checkbox:		{ Property: 'checked', 			Type: 'bool' }
	},

	initialize: function() {
		this.pref = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
	},

	InitializeDialog: function(dialog) {
		$A(dialog.document.querySelectorAll('*[prefstring]')).forEach( function(elem) {
			if(!this.TypeMap[elem.tagName])
				return;

			elem[this.TypeMap[elem.tagName].Property] = this.GetPrefValue(elem);
		}, this );
	},

	/* Gets the preference for the given element, put here so as to be over-ridable by sub-classes */
	GetPrefValue: function(elem) {
		switch(this.pref.getPrefType(elem.getAttribute('prefstring'))) {
			case this.pref.PREF_INT:	return this.pref.getIntPref(elem.getAttribute('prefstring'));
			case this.pref.PREF_BOOL:	return this.pref.getBoolPref(elem.getAttribute('prefstring'));
			case this.pref.PREF_STRING:	return this.pref.getCharPref(elem.getAttribute('prefstring'));
		}
	},
	
	/* Saves the settings in the dialog to the preferences store */
	SavePrefsFromDialog: function(dialog) {
		$A(dialog.document.querySelectorAll('*[prefstring]')).forEach( function(elem) {
			if(!this.TypeMap[elem.tagName])
				return;

			this.SetPrefValue(elem, elem[this.TypeMap[elem.tagName].Property]);
		}, this );
	},
	/* Saves the preference for the given element, put here so as to be over-ridable by sub-classes */
	SetPrefValue: function(elem, value) {
		switch(this.pref.getPrefType(elem.getAttribute('prefstring')) || this.TypeMap[elem.tagName].Type) {
			case this.pref.PREF_INT:		this.pref.setIntPref(elem.getAttribute('prefstring'), value);	break;
			case this.pref.PREF_BOOL:		this.pref.setBoolPref(elem.getAttribute('prefstring'), value);	break;
			case this.pref.PREF_STRING:		this.pref.setCharPref(elem.getAttribute('prefstring'), value);	break;
		}
	}
});
